#ifndef BINDING_ALGORITHM_HELPER
#define BINDING_ALGORITHM_HELPER

#include "../types/wfnettypes.h"

#include <coretypes.h>

#include <QtCore/QList>

#define BAH BindingAlgorithmHelper::getInstance()

namespace core
{
class BasicTime;
}

namespace wfnet
{
class Arc;
class Binding;
class Multiset;
class TimedMultiset;

class BindingAlgorithmHelper
{
public:
    static BindingAlgorithmHelper* getInstance();
    static void destroy();

    const int randomMultisetValue(int size) const;

    bool bindFreeVariable(const VariableName& var, const Arc* arc,
        Binding& binding, const core::BasicTime& globalClock,
        core::BasicTime& proposedGlobalClock) const;

    bool bindUnboundVariable(const VariableName& var, const Arc* arc,
        Binding& binding, const core::BasicTime& globalClock,
        core::BasicTime& proposedGlobalClock) const;

    bool bindRandomly(const VariableName& var, const core::TypeName& type,
        bool timed, Binding& binding, const core::BasicTime& globalClock,
        core::BasicTime& proposedGlobalClock) const;

    template <typename T>
    bool bindFromConstraint(const VariableName& var, const T& ms,
        Binding& binding, const core::BasicTime& globalClock,
        core::BasicTime& proposedGlobalClock) const;

    template <typename T>
    void getMultisetFromPlace(const Arc* arc, T& ms) const;

    template <typename T>
    void getInstersection(const QList<const Arc* >& arcs,
        T& intersectedMs) const;

    void setBitInBitArray(int* bitarray, int index) const;
    bool checkBitInBitArray(int* bitarray, int index) const;

    void getMinimumTime(const QList<const Arc* >& arcs,
        core::BasicTime& clock) const;

private:
    BindingAlgorithmHelper();
    ~BindingAlgorithmHelper();

    void getMultisetFromPlace(const Arc* arc, Multiset& ms) const;
    void getMultisetFromPlace(const Arc* arc, TimedMultiset& ms) const;
    bool bindFromConstraint(const VariableName& var, const Multiset& ms,
        Binding& binding, const core::BasicTime& globalClock,
        core::BasicTime& proposedGlobalClock) const;
    bool bindFromConstraint(const VariableName& var,
        const TimedMultiset& ms, Binding& binding,
        const core::BasicTime& globalClock,
        core::BasicTime& proposedGlobalClock) const;
};

} // namespace wfnet

#endif
